// Intel 8250 serial port (UART).8250串口控制台

//
#include <types.h>
//
//
#include <defs.h>
//
#include <param.h>
//
#include <spinlock.h>
#include <traps.h>
//
//
#include <sleeplock.h>
//
#include <fs.h>
//
#include <file.h>
//
#include <mmu.h>
//
#include <proc.h>
//
#include <x86.h>

#define COM1 0x3f8

static int uart;  // is there a uart?

void uartinit(void) {
	char *p;

	// Turn off the FIFO
	outb(COM1 + 2, 0);

	// 9600 baud, 8 data bits, 1 stop bit, parity off.
	outb(COM1 + 3, 0x80);  // Unlock divisor
	outb(COM1 + 0, 115200 / 9600);
	outb(COM1 + 1, 0);
	outb(COM1 + 3, 0x03);  // Lock divisor, 8 data bits.
	outb(COM1 + 4, 0);
	outb(COM1 + 1, 0x01);  // Enable receive interrupts.

	// If status is 0xFF, no serial port.
	if (inb(COM1 + 5) == 0xFF)
		return;
	uart = 1;

	// Acknowledge pre-existing interrupt conditions;
	// enable interrupts.
	inb(COM1 + 2);
	inb(COM1 + 0);
	ioapicenable(IRQ_COM1, 0);

	// Announce that we're here.
	//找到串口控制台就往那里发消息
	//这个循环打印数组的技巧绝了
	for (p = "xv6...\n"; *p; p++)
		uartputc(*p);
}

void uartputc(int c) {
	int i;

	if (!uart)
		return;
	for (i = 0; i < 128 && !(inb(COM1 + 5) & 0x20); i++)
		microdelay(10);
	outb(COM1 + 0, c);
}

static int
uartgetc(void) {
	if (!uart)
		return -1;
	if (!(inb(COM1 + 5) & 0x01))
		return -1;
	return inb(COM1 + 0);
}

void uartintr(void) {
	consoleintr(uartgetc);
}
